import { MediaStreamManager } from "./media-stream-manager";

export type IceServerConfig = {
    iceServers: RTCIceServer[];
}

export class PeerConnectionManager { 
    private pc : RTCPeerConnection;
    private iceServerConfig: IceServerConfig;
    private mediaStreamManager: MediaStreamManager;
    private onIceCandidate: (candidate: RTCIceCandidate) => void;
    private onTrack: (stream: MediaStream) => void;

    constructor(
        config: IceServerConfig,
        mediaStreamManager: MediaStreamManager,
        onIceCandidate: (candidate: RTCIceCandidate) => void,
        onTrack: (stream: MediaStream) => void
    ) {
        this.iceServerConfig = config;
        this.mediaStreamManager = mediaStreamManager;
        this.onIceCandidate = onIceCandidate
        this.onTrack = onTrack
        this.pc = this.createPeerConnection(this.iceServerConfig);

    }

    private createPeerConnection(config:RTCConfiguration){
        const pc =  new RTCPeerConnection(config);

        pc.onicecandidate = (event) => { 
            if (event.candidate) {
                console.log(event)
                this.onIceCandidate(event.candidate);
            }
        };

        pc.oniceconnectionstatechange = () => { 
            const iceState = this.pc.iceConnectionState;
            console.log("oniceconnectionstatechange ICE connection state:", iceState);
            this.handleIcetateChanged(iceState);
        }

        pc.ontrack = (event) => { 
            if (event.streams && event.streams[0]) {
                this.onTrack(event.streams[0]);
            }
        };

        return pc;
    }

    public async addLocalTrack():Promise<void>{
        const localStream = await this.mediaStreamManager.getLocalStream();
        const existingSenders = this.pc.getSenders();
        localStream.getTracks().forEach((track) => {
            const isTrackAlreadyAdded = existingSenders.some(sender => sender.track === track);
            
            if (!isTrackAlreadyAdded) {
                this.pc.addTrack(track, localStream);
            }
        });
    }

    // 这里以下几个方法需要try catch后throw吗，但是只是log一下，外部调用还得catch，感觉很多余
    public async createOffer(): Promise<RTCSessionDescriptionInit> {
        await this.addLocalTrack();
        const offer = await this.pc.createOffer()
        await this.pc.setLocalDescription(offer);
        return offer;
    }

    public async createAnswer(): Promise<RTCSessionDescriptionInit> {
        await this.addLocalTrack();
        const answer = await this.pc.createAnswer();
        await this.pc.setLocalDescription(answer);
        return answer;
    }

    public async setRemoteDescription(description: RTCSessionDescriptionInit): Promise<void> {
        await this.pc.setRemoteDescription(description);
    }

    public async addIceCandidate(candidate: RTCIceCandidate): Promise<void> {
        await this.pc.addIceCandidate(candidate);
    }

    public close(){
        this.pc.close();
    }

    private handleIcetateChanged(iceState: RTCIceConnectionState){
        switch (iceState) {
            case "connected":
            console.log("ICE connection established");
            // 连接已建立，可以开始传输数据
            break;
            case "completed":
            console.log("ICE connection completed");
            // ICE 候选收集完成
            break;
            case "disconnected":
            console.log("ICE connection disconnected");
            // 连接断开，可能需要重连逻辑
            break;
            case "failed":
            console.error("ICE connection failed");
            // 连接失败，可能需要重新建立连接
            break;
            case "closed":
            console.log("ICE connection closed");
            // 断开连接，可以重新建立连接
            break;
            default:
            console.log("Ice connection state:", iceState);
        }
    }

}